package com.funny.stock.data.collect.source;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.funny.stock.base.util.DateUtil;
import com.funny.stock.base.util.PropertiesCopyUtil;
import com.funny.stock.data.collect.IStockDataSource;
import com.funny.stock.data.collect.bean.NetsStockDayResult;
import com.funny.stock.data.dao.entity.StockDayDataDO;
import com.funny.stock.data.dao.repo.StockDayDataRepository;
import com.funny.stock.data.vo.RealtimeStockData;
import com.funny.stock.data.vo.Stock;
import com.funny.stock.data.vo.StockDayData;
import com.funny.stock.data.vo.StockStatus;
import com.funny.stock.data.vo.StockType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

/**
 * 网易的股票接口
 *
 * @author pengl
 * @date 2020/05/03
 **/
@Component
public class NetsStockDataSource implements IStockDataSource {

    private static final String BASE_URL = "http://img1.money.126.net/data/";
    private static final String API_BASE_URL = "http://api.money.126.net/data/feed/";

    public static final Logger logger = LoggerFactory.getLogger(NetsStockDataSource.class);

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    StockDayDataRepository repository;

    @Override
    public List<Stock> getOnlineStockList(int page, int pageSize, StockType type) {
        return null;
    }

    @Override
    public Stock getStock(String code, StockType type) {

        String url = buildToDayUrl(code, type);

        NetsStockDayResult dayResult = restTemplate.getForObject(url, NetsStockDayResult.class);

        Stock stock = getStock(dayResult);
        stock.setMarket(type.getType());

        return stock;
    }



    @Override
    public List<StockDayData> getStockDataByDate(String code, StockType type, Date startDate, Date endDate) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        int startYear = calendar.get(Calendar.YEAR);

        calendar.setTime(endDate);
        int endYear = calendar.get(Calendar.YEAR);

        logger.info("startYear:"+startYear);
        logger.info("endYear:"+endYear);

//        List<StockDayData> finalDataList = new ArrayList<>();

        if(endYear - startYear >= 5){
            //todo throw Exception
//            return null;
        }

        for (int i = startYear; i <= endYear; i++) {
            List<StockDayDataDO> list = repository.queryAllByDateLike(code, i+"");
            if(!list.isEmpty()){
                logger.info("data exists on " + i);
               continue;
            }

            logger.info("load net data on " + i);
            loadDataByDate(code, type, startYear);
        }



//        return finalDataList;

        return null;
    }

    private void loadDataByDate(String code, StockType type, int startYear) {
        String url = buildHistoryDayUrl(code, type, startYear);
        NetsStockDayResult result = restTemplate.getForObject(url, NetsStockDayResult.class);

        String name = result.getName();
        String symbol = result.getSymbol();

        List<List<String>> data = result.getData();
        data.forEach(item -> {
            StockDayData stockDayData = getStockDayData(type, name, symbol, item);
            StockDayDataDO stockDayDataDO = PropertiesCopyUtil.copyProperties(stockDayData, StockDayDataDO.class);
//                repository.save(stockDayDataDO);

            //todo 只保存没有的年份数据
//            int finalStart = endYear;

            String date = DateUtil.date2yyyyMMdd(stockDayDataDO.getDate());
            StockDayDataDO queryDO = repository.queryDate(stockDayDataDO.getCode(), date);
            if(queryDO != null){
                stockDayDataDO.setId(queryDO.getId());
            }

            repository.save(stockDayDataDO);
        });
    }

    private StockDayData getStockDayData(StockType type, String name, String code, List<String> result) {
        StockDayData data = new StockDayData();
        data.setName(name);
        data.setCode(code);
        data.setMarket(type.getType());

        Date date = DateUtil.string2Date(result.get(0), "yyyyMMdd");
        data.setDate(date);

        data.setOpenPrice(new BigDecimal(result.get(1)));
        data.setClosePrice(new BigDecimal(result.get(2)));
        data.setMaxPrice(new BigDecimal(result.get(3)));
        data.setLowPrice(new BigDecimal(result.get(4)));

        data.setTradeNum(Integer.valueOf(result.get(5)));
        data.setIncreasePer(new BigDecimal(result.get(6)));

        return data;
    }

    private Stock getStock(NetsStockDayResult dayResult) {
        Stock stock = new Stock();
        stock.setName(dayResult.getName());
        stock.setCode(dayResult.getSymbol());
        return stock;
    }

    private String buildHistoryDayUrl(String code, StockType type, int year){
        String url = BASE_URL + "hs/kline/day/history/%s/%s.json";
        code = code.replaceAll(StockType.SZ.getType(),"");
        code = code.replaceAll(StockType.SH.getType(),"");

        String typeCode = getTypeCode(code,type);

        return String.format(url,year+"",typeCode);
    }

    private String buildToDayUrl(String code, StockType type){
        String url = BASE_URL + "hs/time/today/%s.json";
        code = code.replaceAll(StockType.SZ.getType(),"");
        code = code.replaceAll(StockType.SH.getType(),"");

        String typeCode = getTypeCode(code,type);

        return String.format(url,typeCode);
    }

    private String getTypeCode(String code, StockType stockType){
        return stockType.getNumberPrefix() + code;
    }

    @Override
    public StockStatus getStockStatus() {
        //http://api.money.126.net/data/feed/MARKET_HS
//        String randomText = RandomStringUtils.randomAlphanumeric(14);
//        String url = API_BASE_URL + "MARKET_HS?callback=ne" + randomText;
        String url = API_BASE_URL + "MARKET_HS";
        String result = restTemplate.getForObject(url, String.class);
        String json = parseResultJson(result);

        JSONObject jsonObject = JSON.parseObject(json);
        JSONObject data = jsonObject.getJSONObject("MARKET_HS");
        if(data != null){
            String status = data.getString("status");
//            String time = data.getString("update");

            return StockStatus.of(status);
        }
        return null;
    }

    @Override
    public Map<String,RealtimeStockData> getStockDataList(List<Stock> stocks) {
        //http://api.money.126.net/data/feed/1002151,0600036
        Map<String,RealtimeStockData> dataMap = new HashMap<>();
        if(stocks.size() == 0) return dataMap;

        StringJoiner joiner = new StringJoiner(",");
        for (Stock stock : stocks) {
            String codePrefix = "0";
            if(StockType.SZ.getType().equals(stock.getMarket())){
                codePrefix = "1";
            }
            joiner.add(codePrefix + stock.getCode());
        }
        String codes = joiner.toString();

        String url = API_BASE_URL + codes;
        String result = restTemplate.getForObject(url, String.class);
        String resultJson = parseResultJson(result);

        JSONObject jsonObject = JSON.parseObject(resultJson);
        for (String key : jsonObject.keySet()) {
            JSONObject valueObj = jsonObject.getJSONObject(key);
            RealtimeStockData stockData = valueObj.toJavaObject(RealtimeStockData.class);
            //codePrefix
            dataMap.put(key.substring(1), stockData);
        }

        return dataMap;
    }

    @Override
    public RealtimeStockData getRealtimeData(String code, StockType type) {
        String codes = type.getNumberPrefix() + code;

        String url = API_BASE_URL + codes;
        String result = restTemplate.getForObject(url, String.class);
        String resultJson = parseResultJson(result);

        JSONObject jsonObject = JSON.parseObject(resultJson);
        for (String key : jsonObject.keySet()) {
            JSONObject valueObj = jsonObject.getJSONObject(key);
            RealtimeStockData stockData = valueObj.toJavaObject(RealtimeStockData.class);
            return stockData;
        }

        return null;
    }

    private String parseResultJson(String result){
        int firstIndex = result.indexOf("{");
        int lastIndex = result.lastIndexOf("}");
        if(firstIndex == -1 || lastIndex == -1) {
            logger.info("parseResultJson error:{}",result);
            return null;
        }
        return result.substring(firstIndex, lastIndex + 1);
    }

}
